﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Compilex.Syntatic
{
    public class Scope
    {
        public Scope()
        {
            this.SymbolTable = new SymbolTable();
        }
        public SymbolTable SymbolTable { get; set; }
        public Scope ParentScope { get; set; }

        public bool IsDeclaredHere(SymbolClass symClass, string id)
        {
            return TryGetDeclarationHere(symClass, id) != null;
        }

        public Symbol GetDeclarationHere(SymbolClass symClass, string id)
        {
            Symbol sym = TryGetDeclarationHere(symClass, id);
            if (sym != null)
                return sym;
            else
                throw new InternalSyntaticException("Símbolo " + id + " não foi definido neste escopo");
        }

        public Symbol TryGetDeclarationHere(SymbolClass symClass, string id)
        {
            if (SymbolTable.IsDeclared(symClass, id))
                return SymbolTable[id];
            else
                return null;
        }

        public Symbol GetDeclarationAnywhere(SymbolClass symClass, string id)
        {
            Symbol sym = TryGetDeclarationAnywhere(symClass, id);
            if (sym != null)
                return sym;
            else
                throw new SyntaticException("Símbolo " + id + " não foi definido em nenhum escopo");
        }

        public Symbol TryGetDeclarationAnywhere(SymbolClass symClass, string id)
        {
            Symbol symbol = TryGetDeclarationHere(symClass, id);
            if (symbol == null)
            {
                if (ParentScope != null)
                {
                    return ParentScope.TryGetDeclarationAnywhere(symClass, id);
                }
                else
                {
                    return null;
                }
            }
            else
                return symbol;
        }

        public bool IsDeclaredAnywhere(SymbolClass symClass, string id)
        {
            return TryGetDeclarationAnywhere(symClass, id) != null;
        }

        public Scope GetDeclaringScope(SymbolClass symClass, string id)
        {
            if (IsDeclaredHere(symClass, id))
                return this;
            else
            {
                if (ParentScope == null)
                {
                    return null;
                }
                else
                {
                    return ParentScope.GetDeclaringScope(symClass, id);
                }
            }
        }
    }
}
